package com.example.graduation.service.impl;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.auth0.jwt.JWTCreator;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.graduation.entity.Notice;
import com.example.graduation.entity.Shop;
import com.example.graduation.entity.User;
import com.example.graduation.exception.MyException;
import com.example.graduation.mapper.NoticeMapper;
import com.example.graduation.mapper.ShopMapper;
import com.example.graduation.mapper.UserMapper;
import com.example.graduation.service.NoticeService;
import com.example.graduation.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.graduation.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.annotation.Transient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xyc
 * @since 2022-02-11
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Value("${wx.appid}")
    private String appId;

    @Value("${wx.secret}")
    private String secret;

    @Resource
    private UserMapper userMapper;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private EmailSender emailSender;

    @Resource
    private ShopMapper shopMapper;

    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private NoticeService noticeService;

    @Resource
    private NoticeMapper noticeMapper;

    /**
     * 根据微信临时授权码获取openId
     * 因为openId是唯一的，所以他也可以作为一个登录的唯一凭证
     *
     * @param code
     * @return {@link String}
     * @author xieyucan
     * CreateDate 2022/2/11 16:56
     */
    private String getOpenId(String code) {
        String url = "https://api.weixin.qq.com/sns/jscode2session";
        HashMap map = new HashMap();
        map.put("appid", appId);
        map.put("secret", secret);
        map.put("js_code", code);
        map.put("grant_type", "authorization_code");
        String post = HttpUtil.post(url, map);
        //将String类型的post转换为json对象，有利于我们利用键值对获取openid
        JSONObject jsonObject = JSONUtil.parseObj(post);
        String openid = (String) jsonObject.get("openid");
        if (openid == null || openid.length() == 0) {
            throw new RuntimeException("临时登录凭证错误");
        }
        return openid;
    }


    /**
     * 根据openid登录,直接微信登录
     *
     * @param code
     * @return {@link R}
     * @author xieyucan
     * CreateDate 2022/2/12 10:07
     */
    @Override
    public Integer login(String code) {
        String openId = getOpenId(code);
        Integer userId = userMapper.searchUserIdByOpenId(openId);
        if (userId == null) {
            throw new MyException("账号不存在");
        }
        return userId;
    }


    /**
     * 账号密码登录
     * 在这里，我把邮箱和手机号码作为默认的账号
     *
     * @param phoneOrEmail
     * @param password
     * @return
     */
    @Override
    public Integer login(String phoneOrEmail, String password) {

        try {
            Integer userId = null;
            password = DigestUtils.md5DigestAsHex(password.getBytes());
            if (PhoneOrEmailUtil.isPhone(phoneOrEmail)) {
                userId = userMapper.loginByPhone(phoneOrEmail, password);
            } else if (PhoneOrEmailUtil.isEmail(phoneOrEmail)) {
                userId = userMapper.loginByEmail(phoneOrEmail, password);
            } else {
                throw new MyException("信息填写有误");
            }
            if (userId == null) {
                throw new MyException("账号不存在");
            }
            return userId;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }


    /**
     * 用户注册
     * 在这里，我们可以分为除了管理员之外的用户都需要在商城中注册自己的账号，管理员由超级管理员赋予验证码实现在后台系统中实现注册
     * 商家通过在向系统提交申请开店，提交完所有资料，由管理员审核，审核完之后，获得验证码，在商家店铺中实现验证码注册商家号
     *
     * @param phone    手机号码
     * @param email    邮箱号码
     * @param password 用户密码
     * @param code     微信临时授权码
     * @return
     */
    @Override
    public Integer register(String phone, String email, String password, String code,
                            String nickName, String photo) {
        try {
            boolean only = only(phone, email);
            if (only) {
                Integer userId = null;
                String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
                String openId = getOpenId(code);
                userId = userMapper.searchUserIdByOpenId(openId);
                boolean tof = NumUtil.nullNum(userId);
                if (!tof) {
                    HashMap map = new HashMap();
                    map.put("openId", openId);
                    map.put("tel", phone);
                    map.put("photo", photo);
                    map.put("email", email);
                    map.put("password", md5Password);
                    map.put("nickname", nickName);
                    log.info("注册时间为：{}", new Date());
                    map.put("createTime", new Date());
                    map.put("role", "[1]");
                    map.put("root", 0);
                    map.put("status", 0);
                    map.put("points", 0);
                    userMapper.insertUserInfo(map);
                    userId = userMapper.searchUserIdByOpenId(openId);
                    return userId;
                } else {
                    throw new MyException("该微信账号已被注册");
                }

            } else {
                throw new MyException("无法注册");
            }
        } catch (Exception e) {
            throw new MyException(e.getMessage());
        }

    }


    /**
     * 邮箱验证码登录
     *
     * @param email
     * @param code
     * @return {@link Integer}
     * @author xieyucan
     * CreateDate 2022/2/12 14:41
     */
    @Override
    public Integer loginByEmailCode(String email, String code) {
        String key = "xyc_" + email;
        log.info("redis的key值：{}", key);
        try {
            log.info("在redis中获取到的邮箱验证码:{}", redisTemplate.opsForValue().get(key));
            log.info("输入的邮箱验证码为：{}", code);
            Integer count = userMapper.countEmail(email);
            boolean tof = NumUtil.nullNum(count);
            if (tof) {
                if (redisTemplate.opsForValue().get(key).equals(code)) {
                    Integer userId = userMapper.searchIdByEmail(email);
                    return userId;
                } else {
                    throw new MyException("邮箱验证码输入错误");
                }
            } else {
                throw new RuntimeException("该邮箱号码不存在");
            }
        } catch (MyException e) {
            log.error("后端操作异常");
            throw new MyException(e.getMsg());
        }
    }

    /**
     * 发送邮箱验证码
     *
     * @param email
     * @return
     */
    @Override
    public String sendCode(String email) {
        //EmailSender emailSender = new EmailSender();
        String code = emailSender.sendCode(email);
        return code;
    }

    @Override
    public User searchById(int userId) {
        User user = userMapper.searchById(userId);
        return user;
    }

    @Override
    public Set<String> searchPermissionById(int userId) {
        Set<String> strings = userMapper.searchPermissionById(userId);
        return strings;
    }


    /**
     * 验证手机号码，邮箱同时为唯一,且格式正确
     *
     * @param phone
     * @param email
     * @return
     */
    private boolean only(String phone, String email) {
        try {
            if (PhoneOrEmailUtil.isEmail(email) && PhoneOrEmailUtil.isPhone(phone)) {
                Integer countEmail = userMapper.countEmail(email);
                Integer countPhone = userMapper.countPhone(phone);
                if (countEmail == 0 && countPhone == 0) {
                    return true;
                } else {
                    throw new MyException("手机号码或者邮箱号码已经被注册了");
                }
            } else {
                throw new MyException("邮箱或者手机号格式输入有误");
            }
        } catch (MyException e) {
            throw new MyException(e.getMsg());
        }
    }


    /**
     * 查询出超级管理员,在本系统中，超级管理员只有一位
     *
     * @return {@link User}
     * @author xieyucan
     * CreateDate 2022/3/23 13:39
     */
    private User findRoot() {
        try {
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.eq("root", 0);
            User user = userMapper.selectOne(wrapper);
            return user;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("查询失败");
        }
    }


    /**
     * 用户向管理员事情入驻小型购物商城,
     * 在这个方法中，我使用了偷懒的方法，就是直接插入表中
     *
     * @param token
     * @param position
     * @param name
     * @param photo
     * @param content
     * @return {@link Boolean}
     * @author xieyucan
     * CreateDate 2022/3/23 14:28
     */
    @Transient
    @Override
    public Boolean apply(String token, String position, String name, String photo,
                         String content, String license, String shoptype) {
        try {
            int userId = jwtUtil.getUserIdByToken(token);
            Shop shop = new Shop();
            shop.setUserId(userId);
            shop.setPhoto(photo);
            shop.setName(name);
            shop.setLicense(license);
            shop.setContent(content);
            shop.setShoptype(shoptype);
            shop.setPosition(position);
            shop.setCreateTime(System.currentTimeMillis());
            //shop.setStatus(3) 表示还未通过
            shop.setStatus(3);
            shopMapper.insert(shop);
            //TODO 发送消息申请给管理员
            //获取管理员信息
            User root = findRoot();
            Notice notice = new Notice();
            notice.setSendid(userId);
            notice.setAcceptid(root.getId());
            notice.setPhoto(photo);
            //TODO
            // 在这里，我的setContent的内容由content和position组成，里面用$分隔开来
            notice.setContent("内容" + content + "-地址" + position);
            notice.setCreatetime(System.currentTimeMillis());
            notice.setType(4);
            //转发消息给超级管理员
            noticeService.sendNotice(notice);
            return true;
        } catch (Exception e) {
            throw new RuntimeException("操作失败");
        }
    }


    /**
     * 查询用户基本信息
     *
     * @param token
     * @return
     */
    public User findUserInfo(String token) {
        int userId = jwtUtil.getUserIdByToken(token);
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("id", userId);
        User user = userMapper.selectOne(wrapper);
        return user;
    }


    /**
     * 更新用户头像
     *
     * @param token
     * @param photo
     */
    public void changeUserInfo(String token, String photo) {
        int userId = jwtUtil.getUserIdByToken(token);
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("id", userId);
        User user = userMapper.selectOne(wrapper);
        user.setPhoto(photo);
        userMapper.updateById(user);
    }


    /**
     * 修改用户信息
     *
     * @param token
     * @param name
     * @param phone
     * @param sex
     */
    public void changeUserName(String token, String name, String phone, String sex) {
        try {
            int userId = jwtUtil.getUserIdByToken(token);
            User user = userMapper.selectById(userId);
            user.setNickname(name);
            user.setTel(phone);
            user.setSex(sex);
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.eq("id", userId);
            int update = userMapper.update(user, wrapper);
        } catch (Exception e) {
            throw new MyException(e.getMessage());
        }

    }


    /**
     * 插入用户的地址
     *
     * @param token
     * @param lat
     * @param lon
     */
    public void position1(String token, Double lat, Double lon) {
        try {
            int userId = jwtUtil.getUserIdByToken(token);
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.eq("id", userId);
            User user = userMapper.selectOne(wrapper);
            user.setLat(lat);
            user.setLon(lon);
            userMapper.update(user, wrapper);
        } catch (Exception e) {
            throw new MyException(e.getMessage());
        }
    }


    /**
     * 查询用户列表
     *
     * @return
     */
    public List<User> findUserList() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 0);
        List<User> users = userMapper.selectList(wrapper);
        return users;
    }


    /**
     * 查询用户信息
     *
     * @param id
     * @return
     */
    public User findUser(Integer id) {
        try {
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.eq("id", id);
            User user = userMapper.selectOne(wrapper);
            return user;
        } catch (Exception e) {
            throw new MyException(e.getMessage());
        }

    }


    /**
     * 假删除用户
     *
     * @param id
     */
    public void deleteUser(Integer id) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("id", id);
        User user = userMapper.selectOne(wrapper);
        user.setStatus(true);
        userMapper.update(user, wrapper);
    }


    /**
     * 发送警告消息给用户
     *
     * @param id
     */
    public void warmUser(Integer id, String token) {
        Notice notice = new Notice();
        int userId = jwtUtil.getUserIdByToken(token);
        notice.setSendid(userId);
        notice.setAcceptid(id);
        notice.setContent("请共同维护良好的网络购物环境");
        notice.setType(2);
        notice.setCreatetime(System.currentTimeMillis());
        noticeMapper.insert(notice);
    }

}
